#include <stdint.h>
#include "rugby.h"
#include "errno.h"
#include "appConfig.h"
#include "uart_device.h"

/***************
GPIO1           ->GAP4
GPIO2           ->GAP3
GPIO3           ->GAP1
GPIO4(RXD)      ->GAP0
GPIO5(TXD)      ->GAP2
******/

uartRx_cb_func_t uartRxDownCallback = NULL;
uartTx_cb_func_t uartTxDownCallback = NULL;

int8_t UART_Init(Baudrate_t baudRate, BitSize_t bitSize, Parity_t parity,StopBits_t stopBits)
{
    int8_t result = 0;
#if SYS_MAIN_CLOCK_DIV == CLOCK_DIV_1
    UART_SFRS->UARTBAUD.OSR = BAUDRATE_OSR_16MHZ;
    switch (baudRate){
    case BAUDRATE_9600:
      UART_SFRS->UARTBAUD.BAUDDIV = BAUDRATE_DIV_16MHz_9600;
      break;
    case BAUDRATE_19200:
      UART_SFRS->UARTBAUD.BAUDDIV = BAUDRATE_DIV_16MHz_19200;
      break;
    case BAUDRATE_38400:
      UART_SFRS->UARTBAUD.BAUDDIV = BAUDRATE_DIV_16MHz_38400;
      break;
    case BAUDRATE_57600:
      UART_SFRS->UARTBAUD.BAUDDIV = BAUDRATE_DIV_16MHz_57600;
      break;
    case BAUDRATE_115200:
      UART_SFRS->UARTBAUD.BAUDDIV = BAUDRATE_DIV_16MHz_115200;
      break;
    }
#elif SYS_MAIN_CLOCK_DIV == CLOCK_DIV_2
    UART_SFRS->UARTBAUD.OSR = BAUDRATE_OSR_8MHZ;
    switch (baudRate){
    case BAUDRATE_9600:
      UART_SFRS->UARTBAUD.BAUDDIV = BAUDRATE_DIV_8MHz_9600;
      break;
    case BAUDRATE_19200:
      UART_SFRS->UARTBAUD.BAUDDIV = BAUDRATE_DIV_8MHz_19200;
      break;
    case BAUDRATE_38400:
      UART_SFRS->UARTBAUD.BAUDDIV = BAUDRATE_DIV_8MHz_38400;
      break;
    case BAUDRATE_57600:
      UART_SFRS->UARTBAUD.BAUDDIV = BAUDRATE_DIV_8MHz_57600;
      break;
    case BAUDRATE_115200:
      UART_SFRS->UARTBAUD.BAUDDIV = BAUDRATE_DIV_8MHz_115200;
      break;
    }
#elif SYS_MAIN_CLOCK_DIV == CLOCK_DIV_4
    UART_SFRS->UARTBAUD.OSR = BAUDRATE_OSR_4MHZ;
    switch (baudRate){
    case BAUDRATE_9600:
      UART_SFRS->UARTBAUD.BAUDDIV = BAUDRATE_DIV_4MHz_9600;
      break;
    case BAUDRATE_19200:
      UART_SFRS->UARTBAUD.BAUDDIV = BAUDRATE_DIV_4MHz_19200;
      break;
    case BAUDRATE_38400:
      UART_SFRS->UARTBAUD.BAUDDIV = BAUDRATE_DIV_4MHz_38400;
      break;
    default:
      result = -1;
      break;
    }
#elif SYS_MAIN_CLOCK_DIV == CLOCK_DIV_8
    UART_SFRS->UARTBAUD.OSR = BAUDRATE_OSR_2MHZ;
    switch (baudRate){
    case BAUDRATE_9600:
      UART_SFRS->UARTBAUD.BAUDDIV = BAUDRATE_DIV_2MHz_9600;
      break;
    case BAUDRATE_19200:
      UART_SFRS->UARTBAUD.BAUDDIV = BAUDRATE_DIV_2MHz_19200;
      break;
    case BAUDRATE_38400:
      UART_SFRS->UARTBAUD.BAUDDIV = BAUDRATE_DIV_2MHz_38400;
      break;
    default:
      result = -1;
      break;
    }
#endif
    if (result !=0){
        return result;
    }
    UART_SFRS->MSGCTRL.SIZE = bitSize;
    UART_SFRS->MSGCTRL.STOP = stopBits;
    if (parity == PARITY_NONE){
        UART_SFRS->MSGCTRL.PARENA = 0;
    }else if (parity == PARITY_ODD){
        UART_SFRS->MSGCTRL.PARODD = 1;
        UART_SFRS->MSGCTRL.PARENA = 1;
    }else if (parity == PARITY_EVEN){
        UART_SFRS->MSGCTRL.PARODD = 0;
        UART_SFRS->MSGCTRL.PARENA = 1;
    }
    
    UART_SFRS->FLOWCTRL.UCTSENA = 0;
    UART_SFRS->FLOWCTRL.URTSENA = 0;
    
    IOCTRLA_SFRS->GPIO[0].HWMODE = 1; //RXD->GAP0
    IOCTRLA_SFRS->GPIO[2].HWMODE = 1; //TXD->GAP2
    
    
    UART_SFRS->MSGCTRL.ENABLE = 1;
    uint8_t temp = UART_SFRS->MSGCTRL.ENABLE_STS;
    
    return result;
}


void UART_RegisterIRQ(uartRx_cb_func_t rxDowncallback, uartTx_cb_func_t txDowncallback)
{
    if (rxDowncallback){
        uartRxDownCallback = rxDowncallback;
        UART_SFRS->UARTINT.ACTIVE.RXDONE = 1;
    }
    if (txDowncallback){
        uartTxDownCallback = txDowncallback;
        UART_SFRS->UARTINT.ACTIVE.TXDONE = 1;
    }
    if (rxDowncallback || txDowncallback){
        NVIC_EnableIRQ(UART_IRQn);
    }
}

void UART_UnRegisterIRQ(void)
{
    uartRxDownCallback = NULL;
    uartTxDownCallback = NULL;
    UART_SFRS->UARTINT.ACTIVE.RXDONE = 0;
    UART_SFRS->UARTINT.ACTIVE.TXDONE = 0;
    NVIC_DisableIRQ(UART_IRQn);
}


int8_t UART_SendData(uint8_t *buff, uint16_t length)
{
    uint16_t count = length;
    while(count){
        UART_SFRS->DATA = buff[length - count];
        while(UART_SFRS->UARTINT.STATUS.TXDONE == 0);
        UART_SFRS->UARTINT.CLEAR.TXDONE = 0;
        count --;
    }
    return 0;
}


void UART_Handler(void)
{
    uint8_t data;
    if (UART_SFRS->UARTINT.STATUS.RXDONE){
        data = UART_SFRS->DATA;
        if (uartRxDownCallback){
            uartRxDownCallback(data);
        }
    }
    if (UART_SFRS->UARTINT.STATUS.TXDONE){
        if (uartTxDownCallback){
            uartTxDownCallback();
        }
    }
    UART_SFRS->UARTINT.CLEAR.BYTE = 0;
}




